﻿using Foxit.PDF;
using Foxit.PDF.Imaging;
using Foxit.PDF.PageElements;
using Sustainalytics.ClientDW.Entities;
using Sustainalytics.FileManager;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sustainalytics.Utils;
using Sustainalytics.Companies;
using Sustainalytics.DataLayer.Shared;

namespace Sustainalytics.GCCS
{
    public class GCExportManager : IGCExportManager
    {
        private readonly IFileManager _imageFileManager;
        private readonly IGCOverallCompanySummaryManager _overallCompanySummaryManager;
        private readonly IGCPrincipleSummaryExtendedManager _principleSummaryExtendedManager;
        private readonly IGCPrincipleEventIndicatorExtendedManager _principleEventIndicatorExtendedManager;
        private readonly IGCSourceManager _sourceManager;
        private readonly IRepositoryCollection<GCCurrentQuarter> _currentQuarterRepo;
        private Dictionary<int, string> _pillars;
        private Dictionary<string, FileContents> _images;


        #region Fonts
        private static readonly Font CambriaRegular = GetSystemFont("Cambria");
        private static readonly Font CambriaBold = GetSystemFont("Cambria Bold");

        private static readonly Font CalibriBoldItalic = GetSystemFont("Calibri Bold Italic");
        private static readonly Font CalibriItalic = GetSystemFont("Calibri Italic");
        private static readonly Font CalibriBold = GetSystemFont("Calibri Bold");
        private static readonly Font CalibriRegular = GetSystemFont("Calibri");
        private static readonly Font CalibriLight = GetSystemFont("Calibri Light");


        private static readonly FontFamily CalibriFontFamily = new FontFamily("Calibri", CalibriRegular, CalibriBold, CalibriItalic, CalibriBoldItalic);
        private static readonly FontFamily CalibriLightFontFamily = new FontFamily("Calibri", CalibriLight, CalibriBold, CalibriItalic, CalibriBoldItalic);

        private static Font GetSystemFont(string fontName)
        {
            Font font;

            if (Font.CanLoadSystemFont(fontName))
            {
                font = Font.LoadSystemFont(fontName);
            }
            else
            {
                throw new Exception(string.Format("System Font {0} not found", fontName));
            }

            return font;
        }

        #endregion

        #region Colors

        private static readonly Color DarkGreenColor = new RgbColor(46, 164, 150);
        private static readonly Color LightPillarColor = new RgbColor(148, 149, 153);

        #endregion

        #region Constants

        // Common constants
        private static readonly string SustaynalyticsLogoImageName = "SustaynalyticsLogo.png".ToLowerInvariant();

        private const float DefaultPageMargins = 20;
        private const float LeftMargin = 20f;
        private const float PageWidth = 550f;
        private const float PageHeight = 800f;
        private const float MaxContentHeight = 700f;
        private const float LineSpacing = 5f;
        private const float ParagraphSpacing = 10f;

        private const float LargeHeaderHeight = 70f;
        private const float ShortHeaderHeight = 35f;
        private const float YLargeHeader = 35f;
        private const float YShortHeader = 15f;
        private const float FooterHeight = 20f;
        private const float YFooter = 790f;

        private const string GlobalCompactComplianceProductName = "Global Compact Compliance";
        private const string GlobalImpactRadarProductName = "Global Impact Radar";

        private const string NonCompliantAssessmentText = "Non-compliant";
        private const string GccsOverviewText = "Global Compact Compliance Service Overview";
        private const string GirOverviewText = "Global Impact Radar Overview";

        private const float AreaOneWidth = 180f;
        private const float XTextArea = LeftMargin + AreaOneWidth;
        private const float TextAreaWidth = PageWidth - AreaOneWidth - LeftMargin;
        private const float LineWidth = PageWidth;

        #endregion

        public GCExportManager(
            IRepositoryCollection<GCCurrentQuarter> currentQuarterRepo,
            IFileManager imageFileManager,
            IGCOverallCompanySummaryManager overallCompanySummaryManager,
            IGCPrincipleSummaryExtendedManager principleSummaryExtendedManager,
            IGCPrincipleEventIndicatorExtendedManager principleEventIndicatorExtendedManager,
            IGCSourceManager sourceManager)
        {
            _currentQuarterRepo = currentQuarterRepo;
            _imageFileManager = imageFileManager;
            _overallCompanySummaryManager = overallCompanySummaryManager;
            _principleSummaryExtendedManager = principleSummaryExtendedManager;
            _principleEventIndicatorExtendedManager = principleEventIndicatorExtendedManager;
            _sourceManager = sourceManager;


            // load pillars
            LoadPillars();

            // load image files
            LoadImageFiles();
        }

        private void LoadPillars()
        {
            _pillars = new Dictionary<int, string>
            {
                { 1, "Human Rights" },
                { 2, "Labour Rights" },
                { 3, "Environment" },
                { 4, "Business Ethics" }
            };
        }

        private void LoadImageFiles()
        {
            // get image files
            var imageFiles = this._imageFileManager.GetFiles(string.Empty);

            // foreach image file get its byte
            this._images = imageFiles.ToDictionary(el => el.PathFileName.ToLowerInvariant());
        }

        /// <summary>
        /// Get PDF export.
        /// </summary>
        /// <param name="companyId"> Company for which to create PDF export. </param>
        /// <returns> PDF export data. </returns>
        public byte[] GetPdfExport(List<int> universeIds, Guid companyId, GCAssessment overallAssessment, int? type, bool useGirNaming)
        {
            try
            {
                GCCEventSource.Log.GCExport_GetPdfExport(companyId);

                GCCurrentQuarter currentQuarter = this.GetCurrentQuarter();

                // get company
                GCOverallCompanySummary company = this.GetCompany(universeIds, companyId);

                // get principles
                IEnumerable<GCPrincipleSummaryExtended> principles = this.GetPrinciples(companyId, overallAssessment);

                // get principles indicators
                IEnumerable<GCPrincipleEventIndicatorExtended> principlesIndicators = this.GetPrinciplesIndicators(companyId, overallAssessment);

                // get sources
                IEnumerable<GCSource> sources = this.GetSources(companyId, type, null);

                // generate PDF export
                byte[] pdfExport = this.GeneratePDF(currentQuarter, company, principles, principlesIndicators, sources, overallAssessment, useGirNaming);

                GCCEventSource.Log.GCExport_GetPdfExport_Success(companyId);

                return pdfExport;
            }
            catch (Exception ex)
            {
                GCCEventSource.Log.GCExport_GetPdfExport_Error(companyId, ex);
                throw;
            }
        }

        /// <summary>
        /// Generate PDF report.
        /// </summary>
        public byte[] GeneratePdfReport(GCCurrentQuarter currentQuarter, GCAssessment overallAssessment, bool useGirNaming, GCOverallCompanySummary overallCompanySummary, 
            IEnumerable<GCPrincipleSummaryExtended> principles, 
            IEnumerable<GCPrincipleEventIndicatorExtended> principleEventIndicators, IEnumerable<GCSource> sources)
        {
            try
            {
                GCCEventSource.Log.GCExport_GetPdfExport(overallCompanySummary.Id);

                var pdfReport = GeneratePDF(currentQuarter, overallCompanySummary, principles, principleEventIndicators, sources, overallAssessment, useGirNaming);

                GCCEventSource.Log.GCExport_GetPdfExport_Success(overallCompanySummary.Id);

                return pdfReport;
            }
            catch (Exception ex)
            {
                GCCEventSource.Log.GCExport_GetPdfExport_Error(overallCompanySummary.Id, ex);
                throw;
            }
        }
        
        private GCCurrentQuarter GetCurrentQuarter()
        {
            var currentQuarter = _currentQuarterRepo.ReadAll().FirstOrDefault();

            return currentQuarter;
        }

        private GCOverallCompanySummary GetCompany(List<int> universeIds, Guid companyId)
        {
            GCOverallCompanySummary overallCompanySummary = _overallCompanySummaryManager.GetByCompany(universeIds, companyId, null);
            return overallCompanySummary;
        }

        private IEnumerable<GCPrincipleSummaryExtended> GetPrinciples(Guid companyId, GCAssessment? overallAssessment)
        {
            IEnumerable<GCPrincipleSummaryExtended> principles = this._principleSummaryExtendedManager.GetList(companyId, overallAssessment);
            return principles;
        }

        private IEnumerable<GCPrincipleEventIndicatorExtended> GetPrinciplesIndicators(Guid companyId, GCAssessment overallAssessment)
        {
            IEnumerable<GCPrincipleEventIndicatorExtended> principlesIndicators =
                from pi in this._principleEventIndicatorExtendedManager.GetList(companyId, overallAssessment)
                orderby pi.PrincipleTemplateId, pi.EventIndicatorAssessment, pi.IssueType
                select pi;
                
            return principlesIndicators;
        }

        private IEnumerable<GCSource> GetSources(Guid companyId, int? type, GCAssessment? overallAssessment)
        {
            IEnumerable<GCSource> sources = this._sourceManager.GetList(companyId, type, overallAssessment);
            return sources;
        }

        private byte[] GeneratePDF(GCCurrentQuarter currentQuarter,
            GCOverallCompanySummary company,
            IEnumerable<GCPrincipleSummaryExtended> principles,
            IEnumerable<GCPrincipleEventIndicatorExtended> principlesIndicators,
            IEnumerable<GCSource> sources,
            GCAssessment overallAssessment,
            bool useGirNaming)
        {
            var productName = GlobalCompactComplianceProductName;

            if (useGirNaming)
                productName = GlobalImpactRadarProductName;

            var quarterString = GCCSUtility.GetDefaultFormattedGccsQuarter(currentQuarter.Date);

            var pageParameters = new Tuple<string, string, string>(productName, company.CompanyProfile.Name, quarterString);


            var companyDocumentPages = new List<Page>();

            var page = AddNewPage(DefaultPageMargins, GccsPdfHeaderType.Large, pageParameters);

            companyDocumentPages.Add(page);

            var ySection = LargeHeaderHeight;

            AddOverallSummarySection(company, page.Elements, ref ySection, useGirNaming);
            
            
            AddPrinciplesSummarySection(pageParameters, principles, ref companyDocumentPages, ref page, ref ySection);

            ySection += 0f;
            var remainingHeight = PageHeight - ySection - FooterHeight;

            AddPrinciplesDetailsSection(pageParameters, principles, principlesIndicators, ref companyDocumentPages, ref page, ref remainingHeight, ref ySection);
            AddSourcesSection(pageParameters, sources, overallAssessment, ref companyDocumentPages, ref page, ref remainingHeight, ref ySection);
            AddDisclaimer(pageParameters, ref companyDocumentPages, ref page, ref remainingHeight, ref ySection);

            if (!companyDocumentPages.Any()) return null;

            var doc = new Document();
            companyDocumentPages.ForEach(p => doc.Pages.Add(p));

            return doc.Draw();
        }

        private Page AddNewPage(float margins, GccsPdfHeaderType header, Tuple<string, string, string> pageParameters)
        {
            var page = new Page(PageSize.A4, PageOrientation.Portrait, margins);

            if (header == GccsPdfHeaderType.Large)
            {
                AddLargeHeader(page.Elements, pageParameters);
            }

            if (header == GccsPdfHeaderType.Short)
            {
                AddShortHeader(page.Elements, pageParameters.Item2);
            }

            AddFooter(page.Elements);

            return page;
        }

        private void AddLargeHeader(Group pageElements, Tuple<string, string, string> pageParameters)
        {
            const float labelWidth = 340f;

            const float companyNameHeight = 25f;
            const float companyNameFontSize = 24f;
            const float yCompanyNameOffset = 20f;

            const float reportTitleHeight = 15f;
            const float reportTitleFontSize = 14f;
            const float yReportTitleOffset = 10f;

            const float lineThickness = 3;
            const float yLineOffset = 35f;

            const float xImage = 545f;
            const float yImageOffset = 20f;
            const float logoImageScale = 0.17f;

            var productName = pageParameters.Item1;
            var companyName = pageParameters.Item2;
            var quarterText = pageParameters.Item3;
            var reportTitle = productName + " Report";

            byte[] sustainalyticsLogoImage = this._images[SustaynalyticsLogoImageName].ReadAllBytes();

            pageElements.Add(new Label(companyName, LeftMargin, YLargeHeader - yCompanyNameOffset, labelWidth, companyNameHeight, CambriaRegular, companyNameFontSize, TextAlign.Left, RgbColor.Black));
            pageElements.Add(new Label(string.Format("{0} - {1}", reportTitle, quarterText), LeftMargin, YLargeHeader + yReportTitleOffset, labelWidth, reportTitleHeight, CambriaRegular, reportTitleFontSize, TextAlign.Left, RgbColor.DimGray));
            pageElements.Add(new Line(LeftMargin, YLargeHeader + yLineOffset, LineWidth, YLargeHeader + yLineOffset, lineThickness, RgbColor.DimGray));
            pageElements.Add(new Image(ImageData.GetImage(sustainalyticsLogoImage), xImage, YLargeHeader - yImageOffset, logoImageScale) { Align = Align.Right, VAlign = VAlign.Top });
        }

        private void AddShortHeader(Group pageElements, string companyName)
        {
            const float labelWidth = 340f;

            const float companyNameHeight = 12f;
            const float companyNameFontSize = 9f;

            const float lineThickness = 1;
            const float yLineOffset = 15f;

            pageElements.Add(new Label(companyName, LeftMargin, YShortHeader, labelWidth, companyNameHeight, CalibriRegular, companyNameFontSize, TextAlign.Left, RgbColor.Gray));
            pageElements.Add(new Line(LeftMargin, YShortHeader + yLineOffset, LineWidth, YShortHeader + yLineOffset, lineThickness, RgbColor.Gray));
        }

        private void AddFooter(Group pageElements)
        {
            const float xImageOffset = 85f;
            const float yImageOffset = 9f;
            const float imageScale = 0.08f;
            const float imageWidth = 95f;
            const float lineThickness = 0.5f;
            const float pageNumberWidth = 45f;
            const float lineWidth = PageWidth - pageNumberWidth;

            byte[] sustainalyticsLogoImage = this._images[SustaynalyticsLogoImageName].ReadAllBytes();

            pageElements.Add(new Image(ImageData.GetImage(sustainalyticsLogoImage),
                LeftMargin + xImageOffset, YFooter - yImageOffset, imageScale) { Align = Align.Right, VAlign = VAlign.Top });
            pageElements.Add(new Line(LeftMargin + imageWidth, YFooter, lineWidth, YFooter, lineThickness, RgbColor.Gray));
        }

        private void AddOverallSummarySection(GCOverallCompanySummary overallSummarySection, Group pageElements, ref float ySection, bool useGirNaming)
        {
            const float textWidth = 175f;
            const float assessmentLabelTextHeight = 30f;
            const float yAssessmentLabelOffset = 12f;
            const float assessmentLabelFontSize = 12f;
            const float assessmentTextHeight = 16f;
            const float yAssessmentOffset = 45f;
            const float assessmentFontSize = 14f;

            const float xTextGroupOneOffset = 180f;
            const float yTextGroupOneOffset = 12f;
            const float yTextGroupTwoOffset = 26f;
            const float yTextGroupThirdOffset = 40f;
            const float textHeight = 12f;
            const float textFontSize = 10f;

            const float yDescriptionOffset = 80f;
            const float descriptionHeight = 50f;
            const float descriptionWidth = PageWidth - LeftMargin;

            var calibriFontFamily = new FontFamily("Calibri", CalibriLight, CalibriBold, CalibriItalic, CalibriBoldItalic);
            var style = new FormattedTextAreaStyle(CalibriLightFontFamily, textFontSize, false)
            {
                Paragraph = { Align = TextAlign.Justify, Indent = 0, SpacingAfter = 0, AllowOrphanLines = false }
            };

            pageElements.Add(new FormattedTextArea("<p><b>Sustainalytics’ Overall</b></p><p><b>Assessment:</b></p>",
                LeftMargin, ySection + yAssessmentLabelOffset, textWidth, assessmentLabelTextHeight, calibriFontFamily, assessmentLabelFontSize, false));

            pageElements.Add(new Label(overallSummarySection.OverallCompanyAssessment == GCAssessment.NonCompliant ? NonCompliantAssessmentText : overallSummarySection.OverallCompanyAssessment.ToString(),
                LeftMargin, ySection + yAssessmentOffset, textWidth, assessmentTextHeight, CalibriBold, assessmentFontSize, TextAlign.Left, DarkGreenColor));

            //DISPLAY HEADER

            pageElements.Add(new FormattedTextArea(string.Format("<p>Industry: <b>{0}</b></p>", overallSummarySection.CompanyProfile.Industry),
                LeftMargin + xTextGroupOneOffset, ySection + yTextGroupOneOffset, textWidth, textHeight, calibriFontFamily, textFontSize, false));
            pageElements.Add(new FormattedTextArea(string.Format("<p>Domicile: <b>{0}</b></p>", overallSummarySection.CompanyProfile.Country),
                LeftMargin + xTextGroupOneOffset, ySection + yTextGroupTwoOffset, textWidth, textHeight, calibriFontFamily, textFontSize, false));
     
            if (!useGirNaming)
            {
                var signatorySince = overallSummarySection.GCSignatorySince == null
                    ? "Not a signatory"
                    : string.Format("Signatory since {0}",
                        Convert.ToDateTime(overallSummarySection.GCSignatorySince.Value).ToString("MMM yyyy"));
                pageElements.Add(new FormattedTextArea(string.Format("<p>GC Status: <b>{0}</b></p>", signatorySince),
                    LeftMargin + xTextGroupOneOffset, ySection + yTextGroupThirdOffset, textWidth, textHeight,
                    calibriFontFamily, textFontSize, false));
            }
            
            var businessDescriptionTextArea = new FormattedTextArea(string.Format("<p>{0}</p>", overallSummarySection.CompanyProfile.BusinessDescription), LeftMargin, ySection + yDescriptionOffset, descriptionWidth, descriptionHeight, style);

            var requiredHeight = businessDescriptionTextArea.GetRequiredHeight();
            if (requiredHeight > 150)
                requiredHeight = 150;

            businessDescriptionTextArea = new FormattedTextArea(string.Format("<p>{0}</p>", overallSummarySection.CompanyProfile.BusinessDescription), LeftMargin, ySection + yDescriptionOffset, descriptionWidth, requiredHeight, style);
            
            pageElements.Add(businessDescriptionTextArea);

            ySection = ySection + yDescriptionOffset + requiredHeight;

            //END DISPLAY HEADER
        }

        private void AddPillarsElements(int pillarId, ref Page page, float yPillarElements)
        {
            const float xPillarElementsIncrement = 44f;
            const float yPillarElementsOffset = 45f;
            const float imageScale = 0.1f;
            const float pillarTextWidth = 38f;
            const float pillarTextHeight = 20f;
            const float pillarFontSize = 7f;

            var pillars = _pillars.OrderBy(p => p.Key).Select(p => p.Value).AsEnumerable();
            var selectedPillarName = _pillars[pillarId];
            var xPillarElements = LeftMargin;

            foreach (var pillarName in pillars)
            {
                var pillarImageName = GetPillarImageName(pillarName, pillarName.Equals(selectedPillarName));

                byte[] pillarImage = _images[pillarImageName.ToLowerInvariant()].ReadAllBytes();

                page.Elements.Add(new Image(ImageData.GetImage(pillarImage), xPillarElements, yPillarElements, imageScale)
                {
                    Align = Align.Left,
                    VAlign = VAlign.Top
                });

                var pillarFont = CalibriLight;
                var pillarColor = LightPillarColor;
                if (pillarName.Equals(selectedPillarName))
                {
                    pillarFont = CalibriBold;
                    pillarColor = RgbColor.Black;
                }
                page.Elements.Add(new Label(pillarName, xPillarElements, yPillarElements + yPillarElementsOffset,
                    pillarTextWidth, pillarTextHeight, pillarFont, pillarFontSize, TextAlign.Center, pillarColor));

                xPillarElements += xPillarElementsIncrement;
            }
        }

        private void AddSectionTitle(Tuple<string, string, string> pageParameters, string titleText, ref List<Page> pages, ref Page page, ref float remainingHeight, ref float ySection, bool showTitle)
        {
            const float sectionTitleWidth = PageWidth - LeftMargin;
            const float sectionTitleHeight = 16f;
            const float sectionTitleFontSize = 14f;
            const float ySectionTitleOffset = 40f;
            const float sectionLineThickness = 2f;
            const float ySectionLineOffset = 20f;

            var requiredHeight = 210f; // required height for all title sections

            if (titleText.Contains("Sources"))
                requiredHeight = 130; // required height for sources title section

            if (remainingHeight - requiredHeight <= 0)
            {
                page = AddNewPage(DefaultPageMargins, GccsPdfHeaderType.Short, pageParameters);
                pages.Add(page);

                ySection = ShortHeaderHeight;
                remainingHeight = PageHeight - ShortHeaderHeight - FooterHeight;
            }

            if (!showTitle) return;

            page.Elements.Add(new Label(titleText, LeftMargin, ySection, sectionTitleWidth, sectionTitleHeight,
                CambriaBold, sectionTitleFontSize));
            page.Elements.Add(new Line(LeftMargin, ySection + ySectionLineOffset, LineWidth,
                ySection + ySectionLineOffset, sectionLineThickness, RgbColor.Black));

            ySection += ySectionTitleOffset;
            remainingHeight -= ySectionTitleOffset;
        }

        private void AddPrinciplesSummarySection(Tuple<string, string, string> pageParameters, IEnumerable<GCPrincipleSummaryExtended> principlesSummarySection, ref List<Page> companyDocumentPages, ref Page page, ref float ySection)
        {
            const float assessmentTextAreaHeight = 15f;
            const float assessmentTextAreaFontSize = 10f;
            const float pricipleTextAreaHeight = 28f;
            const float pricipleTextAreaFontSize = 10f;
            const float yPrincipleOffset = 50f;

            var yPrinciple = ySection;
            var remainingHeight = PageHeight - ySection;

            var productName = pageParameters.Item1;

            AddSectionTitle(pageParameters, productName == GlobalCompactComplianceProductName ? GccsOverviewText : GirOverviewText, ref companyDocumentPages, ref page, ref remainingHeight, ref yPrinciple, true);

            var priciples = principlesSummarySection;

            if (!priciples.Any()) return;

            var style = new FormattedTextAreaStyle(CalibriLightFontFamily, pricipleTextAreaFontSize, false)
            {
                Paragraph = { Align = TextAlign.Justify, Indent = 0, SpacingAfter = 0, AllowOrphanLines = false }
            };


            int principleIndex = 0;

            foreach (var principle in priciples)
            {
                principleIndex++;

                AddPillarsElements(principle.Principle.Pillar.Id, ref page, yPrinciple);

                page.Elements.Add(new FormattedTextArea(string.Format("<p><b>Assessment: <font color='#41B1A6'>{0}</font></b></p>",
                    principle.PrincipleAssessment == GCAssessment.Watchlist ? principle.PrincipleAssessment.ToString() : NonCompliantAssessmentText),
                    XTextArea, yPrinciple, TextAreaWidth, assessmentTextAreaHeight, CalibriFontFamily, assessmentTextAreaFontSize, false));

                yPrinciple += assessmentTextAreaHeight;
                remainingHeight -= assessmentTextAreaHeight;

                page.Elements.Add(new FormattedTextArea(string.Format("<p><b>{0}: </b>{1}</p>",
                    productName == GlobalCompactComplianceProductName ? principle.Principle.Name : "principle.PrincipleGirName",
                    productName == GlobalCompactComplianceProductName ? principle.Principle.Description : "principle.PrincipleGirDescription"),
                    XTextArea, yPrinciple, TextAreaWidth, pricipleTextAreaHeight, style));

                yPrinciple += pricipleTextAreaHeight;
                remainingHeight -= pricipleTextAreaHeight;

                if (!string.IsNullOrEmpty(principle.Issue))
                {
                    var issue = string.Format("<p><b>Issue: </b>{0}{1}</p>", 
                        principleIndex > 1 ? string.Format("A {0} issue is that ", principleIndex.GetOrdinalName()) : 
                        string.Empty, principle.Issue.Substring(3));

                    AddFormattedTextArea(pageParameters, ref companyDocumentPages, ref page, ref remainingHeight, issue, ref yPrinciple, false, string.Empty, 0);
                }

                var quarterString = GCCSUtility.GetDefaultFormattedGccsQuarter(principle.PrincipleAssessmentEffectiveSince);

                var assessmentEffectiveSince = string.Format("<p><b>Assessment effective since: </b>{0}</p>",
                    string.IsNullOrEmpty(quarterString) ? "Not a signatory" : quarterString);

                page.Elements.Add(new FormattedTextArea(assessmentEffectiveSince,
                    XTextArea, yPrinciple, TextAreaWidth, assessmentTextAreaHeight, CalibriFontFamily, assessmentTextAreaFontSize, false));

                yPrinciple += assessmentTextAreaHeight + yPrincipleOffset;
                remainingHeight -= assessmentTextAreaHeight - yPrincipleOffset;


                if (!(yPrinciple > MaxContentHeight)) continue;

                page = AddNewPage(DefaultPageMargins, GccsPdfHeaderType.Short, pageParameters);
                companyDocumentPages.Add(page);

                yPrinciple = ShortHeaderHeight;
            }

            ySection = yPrinciple;
        }

        private byte[] GetPillarImage(int pillarId, bool useDarkVersion)
        {
            var pillarName = _pillars[pillarId];
            var pillarImageName = GetPillarImageName(pillarName, useDarkVersion);
            return _images[pillarImageName.ToLowerInvariant()].ReadAllBytes();
        }

        private void AddFormattedTextArea(Tuple<string, string, string> pageParameters, ref List<Page> pages, ref Page page, ref float remainingHeight, string formattedText, ref float yTextArea, bool useBullet, string sectionText, int pillarId)
        {
            const float sectionTextAreaWidth = 150f;
            const float sectionTextAreaHeight = 28f;
            const float sectionTextAreaFontSize = 12f;

            const float paragraphFontSize = 10f;
            const float bulletTextAreaWidth = 10f;
            const float bulletTextAreaHeight = 10f;
            const float yPillarImageOffset = 30f;
            const float pillarImageScale = 0.175f;
            const float xPillarTextAreaOffset = 5f;
            const float yPillarTextAreaOffset = 65f;
            const float pillarFontSize = 10f;
            const float pillarTextAreaWidth = 55f;
            const float pillarTextAreaHeight = 30f;
            const float minimumRequiredHeight = 145f;
            const float minimumAreaHeight = 15f;

            var xTextAreaOffset = 0f;
            var textAreaWidth = TextAreaWidth;

            if (useBullet)
            {
                xTextAreaOffset = 10f;
                textAreaWidth = TextAreaWidth - bulletTextAreaWidth;
            }

            var style = new FormattedTextAreaStyle(CalibriLightFontFamily, paragraphFontSize, false)
            {
                Paragraph = { Align = TextAlign.Justify, Indent = 0, SpacingAfter = 0, AllowOrphanLines = false }
            };


            var formattedTextArea = new FormattedTextArea(formattedText, XTextArea + xTextAreaOffset, yTextArea, textAreaWidth, remainingHeight, style);

            var requiredHeight = (float)Math.Round((decimal)formattedTextArea.GetRequiredHeight(), 0, MidpointRounding.AwayFromZero);

            var textAreaHeight = requiredHeight;
            var goToNextPage = false;

            if (!(useBullet && remainingHeight - minimumAreaHeight > 0))
            {
                if (remainingHeight > minimumRequiredHeight && remainingHeight < requiredHeight)
                    textAreaHeight = minimumRequiredHeight;

                if (remainingHeight - (textAreaHeight + LineSpacing) <= 0)
                {
                    goToNextPage = true;
                }
            }

            if (goToNextPage)
            {
                page = AddNewPage(DefaultPageMargins, GccsPdfHeaderType.Short, pageParameters);
                pages.Add(page);

                yTextArea = ShortHeaderHeight;
                remainingHeight = PageHeight - ShortHeaderHeight - FooterHeight;

                if (pillarId > 0)
                {
                    page.Elements.Add(new FormattedTextArea(string.Format("<p><font color='#A8A9AC'>{0}</font></p>", sectionText),
                        LeftMargin, yTextArea, sectionTextAreaWidth, sectionTextAreaHeight, CalibriLightFontFamily, sectionTextAreaFontSize, false));

                    page.Elements.Add(new Image(ImageData.GetImage(GetPillarImage(pillarId, false)),
                        LeftMargin, yTextArea + yPillarImageOffset, pillarImageScale)
                    {
                        Align = Align.Left,
                        VAlign = VAlign.Top
                    });

                    page.Elements.Add(new Label(_pillars[pillarId],
                        LeftMargin + xPillarTextAreaOffset, yTextArea + yPillarImageOffset + yPillarTextAreaOffset,
                        pillarTextAreaWidth, pillarTextAreaHeight, CalibriLight, pillarFontSize, TextAlign.Center, LightPillarColor));
                }
            }

            formattedTextArea = new FormattedTextArea(formattedText, XTextArea + xTextAreaOffset, yTextArea, textAreaWidth, remainingHeight, style);

            if (useBullet)
                page.Elements.Add(new FormattedTextArea("•", XTextArea, yTextArea, bulletTextAreaWidth, bulletTextAreaHeight, style));

            page.Elements.Add(formattedTextArea);

            remainingHeight -= textAreaHeight + LineSpacing;
            yTextArea += textAreaHeight + LineSpacing;


            var hasOverflowText = formattedTextArea.HasOverflowText();
            if (!hasOverflowText) return;

            if (remainingHeight < minimumRequiredHeight)
            {
                page = AddNewPage(DefaultPageMargins, GccsPdfHeaderType.Short, pageParameters);
                pages.Add(page);

                yTextArea = ShortHeaderHeight;
                remainingHeight = PageHeight - ShortHeaderHeight - FooterHeight;

                if (pillarId > 0)
                {
                    page.Elements.Add(new FormattedTextArea(string.Format("<p><font color='#A8A9AC'>{0}</font></p>", sectionText),
                        LeftMargin, yTextArea, sectionTextAreaWidth, sectionTextAreaHeight, CalibriLightFontFamily, sectionTextAreaFontSize, false));

                    page.Elements.Add(new Image(ImageData.GetImage(GetPillarImage(pillarId, false)),
                        LeftMargin, yTextArea + yPillarImageOffset, pillarImageScale)
                    {
                        Align = Align.Left,
                        VAlign = VAlign.Top
                    });

                    page.Elements.Add(new Label(_pillars[pillarId],
                        LeftMargin + xPillarTextAreaOffset, yTextArea + yPillarImageOffset + yPillarTextAreaOffset,
                        pillarTextAreaWidth, pillarTextAreaHeight, CalibriLight, pillarFontSize, TextAlign.Center, LightPillarColor));
                }
            }

            var overflowFormattedTextArea = formattedTextArea.GetOverflowFormattedTextArea(XTextArea + xTextAreaOffset, yTextArea, requiredHeight);

            if (overflowFormattedTextArea == null) return;

            var requiredOverflowFormattedTextAreaHeight = (float)Math.Round((decimal)overflowFormattedTextArea.GetRequiredHeight(), 0, MidpointRounding.AwayFromZero);

            page.Elements.Add(overflowFormattedTextArea);

            remainingHeight -= requiredOverflowFormattedTextAreaHeight + LineSpacing;
            yTextArea += requiredOverflowFormattedTextAreaHeight + LineSpacing;
        }


        private void AddPrinciplesDetailsSection(Tuple<string, string, string> pageParameters,
            IEnumerable<GCPrincipleSummaryExtended> principlesSummarySection, IEnumerable<GCPrincipleEventIndicatorExtended> principlesDetails,
            ref List<Page> companyDocumentPages, ref Page page, ref float remainingHeight, ref float ySection)
        {

            const float issueTypeTextAreaHeight = 20f;
            const float issueTypeFontSize = 14f;
            const float sectionFontSize = 12f;
            const float sectionTextAreaWidth = 150f;
            const float sectionTextAreaHeight = 28f;

            const float pillarImageScale = 0.175f;
            const float yLightPillar = 175f;
            const float yPillarImageOffset = 20f;

            const string overallAssessmentText = "Assessment:";
            const float xOverallAssessmentOffset = 70f;
            const float yOverallAssessmentTextOffset = 40f;
            const float yOverallAssessmentOffset = 55f;
            const float overallAssessmentHeight = 12f;
            const float overallAssessmentFontSize = 10f;

            const float xPillarNameOffset = 5f;
            const float yPillarNameOffset = 95f;
            const float pillarNameWidth = 55f;
            const float pillarNameHeight = 30f;
            const float pillarNameFontSize = 10f;

            const string analysisOfIssueText = "Analysis of Issue";
            const string analysisOfCompanyManagementText = "<p>Analysis of Company</p><p>Management</p>";
            const string assessmentSummaryAndConclusionText = "<p>Assessment Summary</p><p>and Conclusion</p>";

            const string nonCompliantGccText = "<p><b>Sustainalytics assesses {0} to be in violation of Principle {1} of the {2}, which requires that {3}</b></p>";
            const string watchlistGccText = "<p><b>Sustainalytics assesses {0} to be at risk of violating Principle {1} of the {2}, which requires that {3}</b></p>";
            const string nonCompliantGirText = "<p><b>Sustainalytics assesses {0} to be in violation of Criteria {1} of the {2}, which requires that {3}</b></p>";
            const string watchlistGirText = "<p><b>Sustainalytics assesses {0} to be at risk of violating Criteria {1} of the {2}, which requires that {3}</b></p>";


            const float requiredSubtitleHeight = 25;

            var productName = pageParameters.Item1;
            var companyName = pageParameters.Item2;

            var lastPrincipleTemplateId = 0;

            // create a dictionary with principles
            Dictionary<int, GCPrincipleSummaryExtended> principlesDic = principlesSummarySection.ToDictionary(el => el.Principle.Id);

            int index = 0;

            foreach (var principlesDetail in principlesDetails)
            {
                var principleSummary = principlesDic[principlesDetail.PrincipleTemplateId];

                var showTitle = lastPrincipleTemplateId != principlesDetail.PrincipleTemplateId;
                lastPrincipleTemplateId = principlesDetail.PrincipleTemplateId;


                AddSectionTitle(pageParameters, string.Format("{0}: {1}", principlesDetail.EventIndicatorAssessment == GCAssessment.Watchlist ? principlesDetail.EventIndicatorAssessment.ToString() : NonCompliantAssessmentText, productName == GlobalCompactComplianceProductName ? principleSummary.Principle.Name : "principlesDetail.PrincipleGirName"), ref companyDocumentPages, ref page, ref remainingHeight, ref ySection, showTitle);

                var sectionText = analysisOfIssueText;

                page.Elements.Add(new FormattedTextArea(string.Format("<p><b>{0}</b></p>", analysisOfIssueText),
                    LeftMargin, ySection, sectionTextAreaWidth, sectionTextAreaHeight, CalibriFontFamily, sectionFontSize, false));

                page.Elements.Add(new Image(ImageData.GetImage(GetPillarImage(principleSummary.Principle.Pillar.Id, true)),
                    LeftMargin, ySection + yPillarImageOffset, pillarImageScale)
                {
                    Align = Align.Left,
                    VAlign = VAlign.Top
                });
                page.Elements.Add(new Label(overallAssessmentText,
                    LeftMargin + xOverallAssessmentOffset, ySection + yOverallAssessmentTextOffset, sectionTextAreaWidth, overallAssessmentHeight,
                    CalibriLight, overallAssessmentFontSize, TextAlign.Left, RgbColor.Black));
                page.Elements.Add(new Label(principlesDetail.EventIndicatorAssessment == GCAssessment.Watchlist ? principlesDetail.EventIndicatorAssessment.ToString() : NonCompliantAssessmentText,
                    LeftMargin + xOverallAssessmentOffset, ySection + yOverallAssessmentOffset, sectionTextAreaWidth, overallAssessmentHeight,
                    CalibriBold, overallAssessmentFontSize, TextAlign.Left, RgbColor.Black));

                page.Elements.Add(new Label(_pillars[principleSummary.Principle.Pillar.Id],
                    LeftMargin + xPillarNameOffset, ySection + yPillarNameOffset, pillarNameWidth, pillarNameHeight,
                    CalibriBold, pillarNameFontSize, TextAlign.Center, RgbColor.Black));

                var analysisOfIssueStartPageNumber = companyDocumentPages.Count();

                var yAnalysisOfIssue = ySection + yPillarNameOffset + pillarNameHeight + ParagraphSpacing;

                page.Elements.Add(new FormattedTextArea(string.Format("<p><b>{0}</b></p>", principlesDetail.IssueType),
                    XTextArea, ySection, TextAreaWidth, issueTypeTextAreaHeight, CalibriFontFamily, issueTypeFontSize, false));

                ySection += issueTypeTextAreaHeight;
                remainingHeight -= issueTypeTextAreaHeight;

                if (!string.IsNullOrEmpty(principlesDetail.EventSummary))
                    AddFormattedTextArea(pageParameters, ref companyDocumentPages, ref page, ref remainingHeight,
                        string.Format("<p>{0}</p>", principlesDetail.EventSummary), ref ySection, false, sectionText, principleSummary.Principle.Pillar.Id);

                ySection += ParagraphSpacing;
                remainingHeight -= ParagraphSpacing;

                if (!string.IsNullOrEmpty(principlesDetail.ImpactSummary))
                    AddFormattedTextArea(pageParameters, ref companyDocumentPages, ref page, ref remainingHeight,
                        string.Format("<p><b>{0}</b></p>", principlesDetail.ImpactSummary), ref ySection, false, sectionText, principleSummary.Principle.Pillar.Id);

                foreach (var impactComment in principlesDetail.ImpactComments)
                {
                    if (!string.IsNullOrEmpty(impactComment))
                        AddFormattedTextArea(pageParameters, ref companyDocumentPages, ref page, ref remainingHeight,
                            string.Format("<p>{0}</p>", impactComment), ref ySection, true, sectionText, principleSummary.Principle.Pillar.Id);
                }


                ySection += ParagraphSpacing;
                remainingHeight -= ParagraphSpacing;

                if (ySection < yAnalysisOfIssue && analysisOfIssueStartPageNumber == companyDocumentPages.Count())
                {
                    remainingHeight -= yAnalysisOfIssue - ySection;
                    ySection = yAnalysisOfIssue;
                }

                if (ySection < yLightPillar)
                {
                    remainingHeight -= yLightPillar - ySection;
                    ySection = yLightPillar;
                }

                if (remainingHeight - requiredSubtitleHeight <= 0)
                {
                    page = AddNewPage(DefaultPageMargins, GccsPdfHeaderType.Short, pageParameters);
                    companyDocumentPages.Add(page);

                    ySection = ShortHeaderHeight;
                    remainingHeight = PageHeight - ShortHeaderHeight - FooterHeight;
                }

                page.Elements.Add(new Line(LeftMargin, ySection, LineWidth, ySection, 1f, RgbColor.Black));

                ySection += ParagraphSpacing;
                remainingHeight -= ParagraphSpacing;

                sectionText = analysisOfCompanyManagementText;
                var yAnalysisOfCompanyManagement = ySection + sectionTextAreaHeight + ParagraphSpacing;
                var analysisOfCompanyManagementPageNumber = companyDocumentPages.Count();

                page.Elements.Add(new FormattedTextArea(string.Format("<p><b>{0}</b></p>", analysisOfCompanyManagementText),
                    LeftMargin, ySection, sectionTextAreaWidth, sectionTextAreaHeight, CalibriFontFamily, sectionFontSize, false));

                if (!string.IsNullOrEmpty(principlesDetail.ManagementSummary))
                    AddFormattedTextArea(pageParameters, ref companyDocumentPages, ref page, ref remainingHeight,
                        string.Format("<p><b>{0}</b></p>", principlesDetail.ManagementSummary), ref ySection, false, sectionText, principleSummary.Principle.Pillar.Id);

                foreach (var managementComment in principlesDetail.ManagementComments)
                {
                    if (!string.IsNullOrEmpty(managementComment))
                        AddFormattedTextArea(pageParameters, ref companyDocumentPages, ref page, ref remainingHeight,
                            string.Format("<p>{0}</p>", managementComment), ref ySection, true, sectionText, principleSummary.Principle.Pillar.Id);
                }


                ySection += ParagraphSpacing;
                remainingHeight -= ParagraphSpacing;

                if (ySection < yAnalysisOfCompanyManagement && analysisOfCompanyManagementPageNumber == companyDocumentPages.Count())
                {
                    remainingHeight -= yAnalysisOfCompanyManagement - ySection;
                    ySection = yAnalysisOfCompanyManagement;
                }

                if (ySection < yLightPillar)
                {
                    remainingHeight -= yLightPillar - ySection;
                    ySection = yLightPillar;
                }

                if (remainingHeight - requiredSubtitleHeight <= 0)
                {
                    page = AddNewPage(DefaultPageMargins, GccsPdfHeaderType.Short, pageParameters);
                    companyDocumentPages.Add(page);

                    ySection = ShortHeaderHeight;
                    remainingHeight = PageHeight - ShortHeaderHeight - FooterHeight;
                }

                const int requiredHeight = 130; // required height for assessment summary and conclusion title section

                if (remainingHeight - requiredHeight <= 0)
                {
                    page = AddNewPage(DefaultPageMargins, GccsPdfHeaderType.Short, pageParameters);
                    companyDocumentPages.Add(page);

                    ySection = ShortHeaderHeight;
                    remainingHeight = PageHeight - ShortHeaderHeight - FooterHeight;
                }


                page.Elements.Add(new Line(LeftMargin, ySection, LineWidth, ySection, 1f, RgbColor.Black));

                ySection += ParagraphSpacing;
                remainingHeight -= ParagraphSpacing;

                page.Elements.Add(new FormattedTextArea(string.Format("<p><b>{0}</b></p>", assessmentSummaryAndConclusionText),
                        LeftMargin, ySection, sectionTextAreaWidth, sectionTextAreaHeight, CalibriFontFamily, sectionFontSize, false));


                if (!principlesDic.ContainsKey(principlesDetail.PrincipleTemplateId)) continue;

                sectionText = assessmentSummaryAndConclusionText;

                if (!string.IsNullOrEmpty(principleSummary.AssessmentSummaryAndConclusionIntroductionSentence))
                    AddFormattedTextArea(pageParameters, ref companyDocumentPages, ref page, ref remainingHeight,
                        string.Format("<p><b>{0}</b></p>",
                            principleSummary.AssessmentSummaryAndConclusionIntroductionSentence), ref ySection, false,
                        sectionText, principleSummary.Principle.Pillar.Id);

                foreach (var assessmentComment in principleSummary.AssessmentComments)
                {
                    if (!string.IsNullOrEmpty(assessmentComment))
                        AddFormattedTextArea(pageParameters, ref companyDocumentPages, ref page, ref remainingHeight,
                            string.Format("<p>{0}</p>", assessmentComment), ref ySection, true, sectionText,
                            principleSummary.Principle.Pillar.Id);
                }


                ySection += ParagraphSpacing;
                remainingHeight -= ParagraphSpacing;

                string conclusionText = null;

                if (productName == GlobalCompactComplianceProductName)
                {
                    var principleNumber = principleSummary.Principle.Name.Split(' ')[3];

                    conclusionText =
                        string.Format(
                            principleSummary.PrincipleAssessment == GCAssessment.Watchlist
                                ? watchlistGccText
                                : nonCompliantGccText,

                            companyName, 
                            principleNumber, 
                            "UN Global Compact",
                            principleSummary.Principle.Description);
                }
                
                if (productName == GlobalImpactRadarProductName)
                {
                    var criteriaNumber = "principle.PrincipleGirName.Split(' ')[1]";

                    conclusionText =
                        string.Format(
                            principleSummary.PrincipleAssessment == GCAssessment.Watchlist
                                ? watchlistGirText
                                : nonCompliantGirText,
                            companyName, criteriaNumber, productName, "principle.PrincipleGirDescription.ToLowerInvariant()");
                }

                AddFormattedTextArea(pageParameters, ref companyDocumentPages, ref page, ref remainingHeight,
                    conclusionText, ref ySection, false, sectionText, principleSummary.Principle.Pillar.Id);

                ySection += ParagraphSpacing * 2;
                remainingHeight -= ParagraphSpacing * 2;

                if (!(ySection < yLightPillar)) continue;

                remainingHeight -= yLightPillar - ySection;
                ySection = yLightPillar;


                index++;
            }
        }

        private void AddSourcesSection(Tuple<string, string, string> pageParameters, IEnumerable<GCSource> sourcesSection, GCAssessment assessment,
            ref List<Page> companyDocumentPages, ref Page page, ref float remainingHeight, ref float ySection)
        {
            const float ySourceHeaderOffset = 30f;
            const float sourceTypeAreaHeight = 14f;
            const float sourceTypeFontSize = 12f;
            const float sourceTextAreaHeight = 50f;
            const float sourceFontSize = 10f;
            const float ySourceTextAreaOffset = 2f;
            const string sourcesText = "Sources";
            const float yStandardTextOffset = 15f;

            AddSectionTitle(pageParameters, sourcesText, ref companyDocumentPages, ref page, ref remainingHeight, ref ySection, true);

            FormattedTextArea formattedTextArea;
            float requiredHeight;

            if (!sourcesSection.Any()) return;

            var primarySources = sourcesSection.Where(s => s.Type == 1)
                                               .OrderBy(s => s.NewsArticleName)
                                               .ToList();
            if (primarySources.Any())
            {
                formattedTextArea = new FormattedTextArea("<p><b>Primary Sources</b></p>",
                        LeftMargin, ySection, PageWidth - LeftMargin, sourceTypeAreaHeight, CalibriFontFamily, sourceTypeFontSize, false);

                page.Elements.Add(formattedTextArea);

                ySection += sourceTypeAreaHeight;
                remainingHeight -= sourceTypeAreaHeight;

                foreach (var source in primarySources)
                {
                    if (remainingHeight - sourceTextAreaHeight <= 0)
                    {
                        page = AddNewPage(DefaultPageMargins, GccsPdfHeaderType.Short, pageParameters);
                        companyDocumentPages.Add(page);

                        ySection = FooterHeight + ySourceHeaderOffset;
                        remainingHeight = PageHeight - ShortHeaderHeight - FooterHeight - ySourceHeaderOffset;
                    }

                    formattedTextArea = new FormattedTextArea(string.Format("<p>{0}</p>", source.NewsArticleName),
                            LeftMargin, ySection, PageWidth - LeftMargin, sourceTextAreaHeight, CalibriLightFontFamily, sourceFontSize, false);

                    requiredHeight = (float)Math.Round((decimal)formattedTextArea.GetRequiredHeight(), 0, MidpointRounding.AwayFromZero);

                    page.Elements.Add(formattedTextArea);

                    ySection += requiredHeight + ySourceTextAreaOffset;
                    remainingHeight -= requiredHeight + ySourceTextAreaOffset;
                }

                ySection += sourceTypeAreaHeight;
                remainingHeight -= sourceTypeAreaHeight;
            }

            var secondarySources = sourcesSection.Where(s => s.Type == 2 && s.EventIndicatorAssessment == assessment)
                                                 .OrderBy(s => s.PublicationDate)
                                                 .ThenBy(s => s.NewsArticleName)
                                                 .ThenBy(s => s.SourceName)
                                                 .ToList();

            if (secondarySources.Any())
            {
                if (primarySources.Any())
                {
                    formattedTextArea = new FormattedTextArea("<p><b>Secondary Sources</b></p>",
                        LeftMargin, ySection, PageWidth - LeftMargin, sourceTypeAreaHeight, CalibriFontFamily,
                        sourceTypeFontSize, false);

                    page.Elements.Add(formattedTextArea);

                    ySection += sourceTypeAreaHeight;
                    remainingHeight -= sourceTypeAreaHeight;
                }

                foreach (var source in secondarySources)
                {
                    if (remainingHeight - sourceTextAreaHeight <= 0)
                    {
                        page = AddNewPage(DefaultPageMargins, GccsPdfHeaderType.Short, pageParameters);
                        companyDocumentPages.Add(page);

                        ySection = FooterHeight + ySourceHeaderOffset;
                        remainingHeight = PageHeight - ShortHeaderHeight - FooterHeight - ySourceHeaderOffset;
                    }

                    formattedTextArea =
                        new FormattedTextArea(
                            string.Format("<p>{0}, {1}, “{2}”</p>",
                            source.PublicationDate.ToString("dd MMMM yyyy"), source.SourceName, source.NewsArticleName),
                            LeftMargin, ySection, PageWidth - LeftMargin, sourceTextAreaHeight, CalibriLightFontFamily,
                            sourceFontSize, false);

                    requiredHeight =
                        (float)
                            Math.Round((decimal)formattedTextArea.GetRequiredHeight(), 0, MidpointRounding.AwayFromZero);

                    page.Elements.Add(formattedTextArea);

                    ySection += requiredHeight + ySourceTextAreaOffset;
                    remainingHeight -= requiredHeight + ySourceTextAreaOffset;
                }
            }
        }

        private void AddDisclaimer(Tuple<string, string, string> pageParameters,
            ref List<Page> companyDocumentPages, ref Page page, ref float remainingHeight, ref float ySection)
        {
            const float ySourceHeaderOffset = 30f;
            const float ySpaceBeforeTitle = 40f;
            const float yTextOffset = 60f;
            const float sourceTypeFontSize = 10f;
            const float titleAreaHeight = 30f;
            const float paragraphAreaHeight = 305f;


            var copyright1 = $"<p><b>Copyright ©{DateTime.UtcNow.Year} Sustainalytics. All rights reserved.</b></p>";

            var copyrightText = new StringBuilder();
            copyrightText.Append(copyright1);
            copyrightText.Append("<p>The ownership and all intellectual property rights to this publication/report and the information contained herein are vested exclusively in Sustainalytics and/or its suppliers. Unless otherwise expressly agreed in writing between you and Sustainalytics, you will not be permitted to use this information otherwise than for internal use, nor will you be permitted to reproduce, disseminate, comingle, create derivative works, furnish in any manner, make available to third parties or publish this publication/report, parts hereof or the information contained herein in any form or in any manner, be it electronically, mechanically, through photocopies, recordings.  The information on which this publication/report is based on reflects the situation as on the date of its elaboration. Such information has – fully or partially – been derived from third parties and is therefore subject to continuous modification. " +
                "THE INFORMATION HEREIN IS PROVIDED SOLELY FOR INFORMATIONAL PURPOSES AND THEREFORE ARE NOT AN OFFER TO BUY OR SELL A SECURITY. NEITHER SUSTAINALYTICS NOR ALL ITS THIRD-PARTY SUPPLIERS PROVIDE INVESTMENT ADVICE (AS DEFINED IN THE APPLICABLE JURISDICTION) OR ANY OTHER FORM OF (FINANCIAL) ADVICE AND NOTHING WITHIN THIS PUBLICATION/REPORT CONSTITUTES SUCH ADVICE. SUSTAINALYTICS OBSERVES THE GREATEST POSSIBLE CARE IN USING INFORMATION, HOWEVER THE INFORMATION IS PROVIDED “AS IS” AND NEITHER SUSTAINALYTICS NOR ITS SUPPLIERS ACCEPT ANY LIABILITY FOR DAMAGE ARISING FROM THE USE OF THIS PUBLICATION/REPORT OR INFORMATION CONTAINED HEREIN IN ANY MANNER WHATSOEVER. MOREOVER, SUSTAINALYTICS AND ALL ITS THIRD-PARTY SUPPLIERS DISCLAIM ANY AND ALL WARRANTIES AND REPRESENTATIONS, EXPRESS OR IMPLIED, INCLUDING ANY WARRANTIES OF MERCHANTIBILITY, COMPLETENESS, ACCURACY OR FITNESS FOR A PARTICULAR PURPOSE.</p>");
            copyrightText.Append("<br><br>");
            copyrightText.Append("<p>This publication/report may contain proprietary information from third parties (Third Party Data) and here you can find additional terms and conditions imposed by the following Third Party Data providers regarding the use of their data:</p>");
            copyrightText.Append("<br>");
            copyrightText.Append("<a href=\"http://www.sustainalytics.com/legal-disclaimers\"><font color=\"F0AB00\"><b>http://www.sustainalytics.com/legal-disclaimers<b></font></a>");
            copyrightText.Append("<p> </p>");

            FormattedTextArea tempTextArea = new FormattedTextArea(copyrightText.ToString(), LeftMargin, ySection, PageWidth - LeftMargin, paragraphAreaHeight, CalibriFontFamily, sourceTypeFontSize, false);

            float requiredHeight = (float)Math.Round((decimal)tempTextArea.GetRequiredHeight(), 0, MidpointRounding.AwayFromZero);

            if (remainingHeight - ySpaceBeforeTitle - titleAreaHeight - requiredHeight <= 0)
            {
                //new page
                page = AddNewPage(DefaultPageMargins, GccsPdfHeaderType.Short, pageParameters);
                companyDocumentPages.Add(page);

                ySection = FooterHeight + ySourceHeaderOffset;
                remainingHeight = PageHeight - ShortHeaderHeight - FooterHeight - ySourceHeaderOffset - ySpaceBeforeTitle - titleAreaHeight - requiredHeight;
            }
            else
            {
                //add on top of the footer
                ySection = PageHeight - titleAreaHeight - requiredHeight - FooterHeight - 10;
                remainingHeight = titleAreaHeight + requiredHeight;
            }

            AddSectionTitle(pageParameters, "Disclaimer", ref companyDocumentPages, ref page, ref remainingHeight, ref ySection, true);

            page.Elements.Add(new FormattedTextArea(copyrightText.ToString(), LeftMargin, ySection, PageWidth - LeftMargin, paragraphAreaHeight, CalibriFontFamily, sourceTypeFontSize, false));
        }

        private string GetPillarImageName(string pillarName, bool useDarkVersion)
        {
            return pillarName.Replace(" ", string.Empty) + (useDarkVersion ? "Dark" : "Light") + ".png";
        }
    }
}
